package com.mcp.converter.domain.parser.impl;

import com.mcp.converter.shared.response.sql.Position;
import com.mcp.converter.shared.response.sql.SQLElement;
import com.mcp.converter.shared.response.sql.SQLParseResult;
import com.mcp.converter.domain.parser.SQLParser;
import com.mcp.converter.domain.rule.compatibility.AbstractFunctionRule;
import com.mcp.converter.domain.rule.compatibility.CompatibilityRule;
import com.mcp.converter.domain.rule.manager.RuleManager;
import com.mcp.converter.shared.enums.SQLElementType;
import com.mcp.converter.shared.enums.SQLType;
import com.mcp.converter.shared.exception.SqlAnalysisException;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Function;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
import net.sf.jsqlparser.statement.create.table.CreateTable;
import net.sf.jsqlparser.statement.delete.Delete;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.statement.update.Update;
import net.sf.jsqlparser.statement.update.UpdateSet;
import net.sf.jsqlparser.util.deparser.ExpressionDeParser;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

/**
 * SQL解析器实现类，基于JSQLParser
 * @author zengxiong
 */
@Service
@Slf4j
public class SQLParserImpl implements SQLParser {
    
    private final RuleManager ruleManager;
    
    public SQLParserImpl(RuleManager ruleManager) {
        this.ruleManager = ruleManager;
    }

    @Override
    public SQLParseResult parse(String sql) throws SqlAnalysisException.SQLParseException {
        if (sql == null || sql.trim().isEmpty()) {
            throw new IllegalArgumentException("SQL语句不能为空");
        }

        try {
            Statement statement = CCJSqlParserUtil.parse(sql);
            SQLParseResult result = new SQLParseResult();
            result.setOriginalSQL(sql);

            SQLType sqlType = determineSQLType(statement);
            result.setSqlType(sqlType);

            // 新增：递归遍历AST，收集函数
            List<SQLElement> elements = new ArrayList<>();
            extractFunctions(statement, elements, sql);
            result.setElements(elements);

            return result;
        } catch (JSQLParserException e) {
            // 使用正则检测补全函数信息
            SQLParseResult result = new SQLParseResult();
            result.setOriginalSQL(sql);
            List<SQLElement> elements = new ArrayList<>();
            extractFunctionsFromFailedSQL(sql, elements);
            result.setElements(elements);
            
            // 重要改动：如果检测到不兼容函数，返回结果而不是抛出异常
            if (!elements.isEmpty()) {
                log.info("SQL解析失败但检测到{}个不兼容函数，返回解析结果用于兼容性检测", elements.size());
                result.setSqlType(SQLType.UNKNOWN);
                result.addAttribute("parseFailure", true);
                result.addAttribute("parseError", e.getMessage());
                return result;
            }
            
            // 如果没有检测到不兼容函数，才抛出异常
            throw new SqlAnalysisException.SQLParseException("SQL解析失败: " + e.getMessage() + ", 且未检测到不兼容函数。", e);
        } catch (Exception e) {
            throw new SqlAnalysisException.SQLParseException("解析SQL时发生异常: " + e.getMessage(), e);
        }
    }

    @Override
    public SQLType getType(String sql) throws SqlAnalysisException.SQLParseException {
        if (sql == null || sql.trim().isEmpty()) {
            throw new IllegalArgumentException("SQL语句不能为空");
        }

        try {
            Statement statement = CCJSqlParserUtil.parse(sql);
            return determineSQLType(statement);
        } catch (JSQLParserException e) {
            throw new SqlAnalysisException.SQLParseException("SQL类型判断失败: " + e.getMessage(), e);
        } catch (Exception e) {
            throw new SqlAnalysisException.SQLParseException("判断SQL类型时发生异常: " + e.getMessage(), e);
        }
    }

    @Override
    public SQLParseResult parseWithFallback(String sql) {
        if (sql == null || sql.trim().isEmpty()) {
            return null;
        }

        try {
            // 先尝试正常解析
            return parse(sql);
        } catch (SqlAnalysisException.SQLParseException e) {
            // 正常解析失败，使用后备机制
            log.debug("正常解析失败，使用后备机制提取函数信息: {}", e.getMessage());
            
            try {
                SQLParseResult result = new SQLParseResult();
                result.setOriginalSQL(sql);
                
                List<SQLElement> elements = new ArrayList<>();
                extractFunctionsFromFailedSQL(sql, elements);
                result.setElements(elements);
                
                // 如果提取到了函数信息，返回结果
                if (!elements.isEmpty()) {
                    log.info("后备解析成功，提取到{}个函数元素", elements.size());
                    return result;
                }
                
            } catch (Exception fallbackException) {
                log.debug("后备解析也失败: {}", fallbackException.getMessage());
            }
        }
        
        return null;
    }

    private SQLType determineSQLType(Statement statement) {
        if (statement == null) {
            return SQLType.UNKNOWN;
        }

        String statementType = statement.getClass().getSimpleName();

        switch (statementType) {
            case "Select":
                return SQLType.SELECT;
            case "Insert":
                return SQLType.INSERT;
            case "Update":
                return SQLType.UPDATE;
            case "Delete":
                return SQLType.DELETE;
            case "CreateTable":
                return SQLType.CREATE_TABLE;
            case "AlterTable":
                return SQLType.ALTER_TABLE;
            case "Drop":
                return SQLType.DROP_TABLE;
            default:
                return SQLType.UNKNOWN;
        }
    }

    /**
     * 计算SQL中某个文本的位置信息
     * @param sql 完整的SQL文本
     * @param target 要查找的目标文本
     * @return 位置信息
     */
    private Position calculatePosition(String sql, String target) {
        if (sql == null || target == null || target.trim().isEmpty()) {
            return new Position(1, 1, 0, 0);
        }

        // 查找目标文本在SQL中的位置
        int startIndex = sql.toUpperCase().indexOf(target.toUpperCase());
        if (startIndex == -1) {
            // 如果直接查找失败，尝试去除空格后查找
            String normalizedTarget = target.replaceAll("\\s+", "\\s*");
            java.util.regex.Pattern pattern = Pattern.compile(normalizedTarget, Pattern.CASE_INSENSITIVE);
            java.util.regex.Matcher matcher = pattern.matcher(sql);
            if (matcher.find()) {
                startIndex = matcher.start();
            } else {
                return new Position(1, 1, 0, target.length());
            }
        }

        int endIndex = startIndex + target.length();
        
        // 计算行号和列号
        int line = 1;
        int column = 1;
        
        for (int i = 0; i < startIndex; i++) {
            if (sql.charAt(i) == '\n') {
                line++;
                column = 1;
            } else {
                column++;
            }
        }
        
        return new Position(line, column, startIndex, endIndex);
    }

    /**
     * 从解析失败的SQL中使用正则表达式提取函数信息
     * 
     * 注意：这与MybatisXMLParserImpl中的后备检测不同：
     * - 这里仅当JSQLParser解析失败时才触发（必要的补救措施）
     * - MybatisXMLParserImpl的后备检测对所有SQL进行额外检查（已证明是多余的）
     * 
     * 当SQL包含复杂语法、MyBatis标签、或JSQLParser不支持的Oracle特有语法时，
     * 解析会失败，但SQL中可能仍包含不兼容函数，此时需要正则表达式提取
     * 
     * @param sql SQL语句
     * @param elements 用于存储提取的元素
     */
    private void extractFunctionsFromFailedSQL(String sql, List<SQLElement> elements) {
        if (sql == null || sql.trim().isEmpty()) {
            return;
        }

        log.info("*** 开始从失败SQL中提取函数: {}", sql);
        
        // 从规则管理器获取所有不兼容函数
        Set<String> incompatibleFunctions = getAllIncompatibleFunctionsFromRules();
        log.info("*** 从规则管理器获取到 {} 个不兼容函数: {}", incompatibleFunctions.size(), incompatibleFunctions);
        
        Set<String> extractedFunctions = new HashSet<>();
        
        // 1. 使用通用的函数调用模式: FUNCTION_NAME(...)
        String functionCallPattern = "(?i)\\b([A-Z_][A-Z0-9_]*)\\s*\\(";
        java.util.regex.Pattern compiledPattern = java.util.regex.Pattern.compile(functionCallPattern);
        java.util.regex.Matcher matcher = compiledPattern.matcher(sql);

        log.info("*** 使用正则表达式匹配函数调用: {}", functionCallPattern);
        while (matcher.find()) {
            String functionName = matcher.group(1);
            log.info("*** 正则表达式匹配到函数: {}", functionName);
            if (functionName != null && !functionName.isEmpty()) {
                functionName = functionName.toUpperCase().trim();
                
                // 只提取在规则中定义为不兼容的函数，并且避免重复添加
                boolean isIncompatible = incompatibleFunctions.contains(functionName);
                boolean notDuplicate = !extractedFunctions.contains(functionName);
                boolean isValid = isValidFunctionName(functionName);

                log.info("*** 函数 {} 检查: isIncompatible={}, notDuplicate={}, isValid={}",
                           functionName, isIncompatible, notDuplicate, isValid);
                
                if (isIncompatible && notDuplicate && isValid) {
                    extractedFunctions.add(functionName);
                    createAndAddFunctionElement(sql, functionName, elements);
                    log.info("*** 成功从失败SQL中提取不兼容函数: {}", functionName);
                }
            }
        }
        
        // 2. 使用更精确的单词边界匹配搜索不兼容函数（避免误判字段名）
        log.info("*** 开始使用单词边界匹配搜索不兼容函数");
        for (String incompatibleFunction : incompatibleFunctions) {
            // 使用单词边界匹配，避免将包含函数名的字段名误判为函数调用
            String wordBoundaryPattern = "(?i)\\b" + Pattern.quote(incompatibleFunction) + "\\b";
            java.util.regex.Pattern wordPattern = java.util.regex.Pattern.compile(wordBoundaryPattern);
            boolean containsFunction = wordPattern.matcher(sql).find();
            boolean notExtracted = !extractedFunctions.contains(incompatibleFunction);

            log.info("*** 检查函数 {}: wordBoundaryMatch={}, notExtracted={}",
                       incompatibleFunction, containsFunction, notExtracted);
            
            if (containsFunction && notExtracted) {
                // 进一步验证：确保不是字段名的一部分
                if (isActualFunctionCall(sql, incompatibleFunction)) {
                    extractedFunctions.add(incompatibleFunction);
                    createAndAddFunctionElement(sql, incompatibleFunction, elements);
                    log.info("*** 在SQL文本中检测到不兼容函数: {}", incompatibleFunction);
                } else {
                    log.info("*** 函数 {} 被识别为字段名或其他非函数用法，跳过", incompatibleFunction);
                }
            }
        }
        
        log.info("*** 函数提取完成，共提取到 {} 个不兼容函数: {}", extractedFunctions.size(), extractedFunctions);
    }
    
    /**
     * 创建函数元素并添加到列表中
     */
    private void createAndAddFunctionElement(String sql, String functionName, List<SQLElement> elements) {
        SQLElement funcElement = new SQLElement(SQLElementType.FUNCTION, functionName);
        funcElement.setValue(extractFunctionCallContext(sql, functionName));
        
        // 设置位置信息
        Position position = calculatePosition(sql, functionName);
        funcElement.setPosition(position);
        
        elements.add(funcElement);
    }
    
    /**
     * 从规则管理器获取所有不兼容函数
     */
    private Set<String> getAllIncompatibleFunctionsFromRules() {
        Set<String> allIncompatibleFunctions = new HashSet<>();
        
        try {
            // 获取所有兼容性规则
            List<CompatibilityRule> rules = ruleManager.queryRules(
                RuleManager.RuleType.COMPATIBILITY, 
                new RuleManager.RuleQueryCondition()
            );
            
            // 遍历所有函数规则，直接获取不兼容函数名称
            for (CompatibilityRule rule : rules) {
                if (rule.getIncompatibilityType() == com.mcp.converter.shared.enums.IncompatibilityType.FUNCTION && rule instanceof AbstractFunctionRule) {
                    AbstractFunctionRule functionRule = (AbstractFunctionRule) rule;
                    Set<String> functionsFromRule = functionRule.getIncompatibleFunctions();
                    allIncompatibleFunctions.addAll(functionsFromRule);
                    log.debug("从规则 {} 获取到 {} 个函数", rule.getName(), functionsFromRule.size());
                }
            }
            
        } catch (Exception e) {
            log.error("从规则管理器获取不兼容函数失败: {}", e.getMessage(), e);
            // 如果获取失败，返回空集合，避免硬编码后备方案
            return new HashSet<>();
        }
        
        return allIncompatibleFunctions;
    }
    
    /**
     * 验证是否为有效的函数名
     */
    private boolean isValidFunctionName(String functionName) {
        if (functionName == null || functionName.isEmpty()) {
            return false;
        }
        
        // 排除一些明显不是函数的关键字
        String[] excludeKeywords = {
            "SELECT", "FROM", "WHERE", "AND", "OR", "NOT", "IS", "NULL", "TRUE", "FALSE",
            "INSERT", "UPDATE", "DELETE", "CREATE", "DROP", "ALTER", "TABLE", "INDEX",
            "PRIMARY", "KEY", "FOREIGN", "REFERENCES", "CONSTRAINT", "UNIQUE", "CHECK",
            "GRANT", "REVOKE", "COMMIT", "ROLLBACK", "SAVEPOINT", "BEGIN", "END",
            "IF", "THEN", "ELSE", "ELSIF", "WHILE", "FOR", "LOOP", "CASE", "WHEN",
            "DISTINCT", "ALL", "ANY", "SOME", "EXISTS", "IN", "BETWEEN", "LIKE",
            "ORDER", "BY", "GROUP", "HAVING", "UNION", "INTERSECT", "MINUS",
            "CONNECT", "START", "WITH", "PRIOR", "LEVEL"
        };
        
        for (String keyword : excludeKeywords) {
            if (keyword.equals(functionName)) {
                return false;
            }
        }
        
        // 函数名应该符合标识符规范
        return functionName.matches("[A-Z_][A-Z0-9_]*");
    }
    
    /**
     * 提取函数调用的上下文信息
     */
    /**
     * 验证是否为实际的函数调用，而不是字段名或其他用法
     * @param sql SQL语句
     * @param functionName 函数名
     * @return 是否为实际函数调用
     */
    private boolean isActualFunctionCall(String sql, String functionName) {
        if (sql == null || functionName == null) {
            return false;
        }
        
        String upperSql = sql.toUpperCase();
        String upperFunction = functionName.toUpperCase();
        
        // 检查是否紧跟着括号（函数调用的典型特征）
        String functionCallPattern = "(?i)\\b" + Pattern.quote(functionName) + "\\s*\\(";
        java.util.regex.Pattern callPattern = java.util.regex.Pattern.compile(functionCallPattern);
        if (callPattern.matcher(sql).find()) {
            return true;
        }
        
        // 对于某些特殊函数（如LEVEL），检查是否在层次查询上下文中使用
        if ("LEVEL".equals(upperFunction)) {
            // LEVEL通常在层次查询中使用，检查是否有CONNECT BY关键字
            if (upperSql.contains("CONNECT BY") || upperSql.contains("START WITH")) {
                return true;
            }
            // 如果只是字段名（如ACTIVITY_LEVEL），则不是函数调用
            return false;
        }
        
        // 对于其他函数，如果没有括号，可能是伪列或特殊用法
        // 这里可以根据具体函数类型进行更精确的判断
        return false;
    }
    
    private String extractFunctionCallContext(String sql, String functionName) {
        if (sql == null || functionName == null) {
            return functionName;
        }
        
        String upperSql = sql.toUpperCase();
        String upperFunctionName = functionName.toUpperCase();
        
        int functionIndex = upperSql.indexOf(upperFunctionName);
        if (functionIndex == -1) {
            return functionName;
        }
        
        // 尝试提取完整的函数调用
        int start = functionIndex;
        int end = functionIndex + functionName.length();
        
        // 寻找函数调用的开始和结束
        if (end < sql.length() && sql.charAt(end) == '(') {
            int parenthesesCount = 1;
            end++;
            
            while (end < sql.length() && parenthesesCount > 0) {
                char c = sql.charAt(end);
                if (c == '(') {
                    parenthesesCount++;
                } else if (c == ')') {
                    parenthesesCount--;
                }
                end++;
            }
        }
        
        // 向前查找函数调用的开始（可能包含一些前缀）
        while (start > 0 && Character.isWhitespace(sql.charAt(start - 1))) {
            start--;
        }
        
        try {
            return sql.substring(start, Math.min(end, sql.length())).trim();
        } catch (Exception e) {
            return functionName;
        }
    }

    /**
     * 递归提取所有函数调用，生成SQLElement
     */
    private void extractFunctions(Statement statement, List<SQLElement> elements, String originalSql) {
        if (statement instanceof Select) {
            Select select = (Select) statement;
            SelectBody selectBody = select.getSelectBody();
            extractFunctionsFromSelectBody(selectBody, elements, originalSql);
        }
        // 处理DELETE语句
        else if (statement instanceof Delete) {
            Delete delete = (Delete) statement;
            if (delete.getWhere() != null) {
                extractFunctionsFromExpression(delete.getWhere(), elements, originalSql);
            }
        }
        // 处理UPDATE语句
        else if (statement instanceof Update) {
            Update update = (Update) statement;
            // 提取SET子句中的函数
            if (update.getUpdateSets() != null) {
                for (UpdateSet updateSet : update.getUpdateSets()) {
                    if (updateSet.getExpressions() != null) {
                        for (Expression expr : updateSet.getExpressions()) {
                            extractFunctionsFromExpression(expr, elements, originalSql);
                        }
                    }
                }
            }
            // 提取WHERE子句中的函数
            if (update.getWhere() != null) {
                extractFunctionsFromExpression(update.getWhere(), elements, originalSql);
            }
        }
        // 处理INSERT语句
        else if (statement instanceof Insert) {
            Insert insert = (Insert) statement;
            // 提取VALUES子句中的函数
            if (insert.getItemsList() instanceof ExpressionList) {
                ExpressionList valuesList = (ExpressionList) insert.getItemsList();
                if (valuesList.getExpressions() != null) {
                    for (Expression expr : valuesList.getExpressions()) {
                        extractFunctionsFromExpression(expr, elements, originalSql);
                    }
                }
            }
            // 提取子查询中的函数（INSERT ... SELECT）
            else if (insert.getItemsList() instanceof SubSelect) {
                SubSelect subSelect = (SubSelect) insert.getItemsList();
                extractFunctionsFromSelectBody(subSelect.getSelectBody(), elements, originalSql);
            }
        }
        // 扩展：提取建表语句中的数据类型和相关表达式
        else if (statement instanceof CreateTable) {
            CreateTable createTable = (CreateTable) statement;
            if (createTable.getColumnDefinitions() != null) {
                for (ColumnDefinition colDef : createTable.getColumnDefinitions()) {
                    String typeName = colDef.getColDataType().getDataType();
                    SQLElement typeElem = new SQLElement(SQLElementType.DATA_TYPE, typeName);
                    typeElem.setValue(typeName);
                    
                    // 设置位置信息
                    Position position = calculatePosition(originalSql, typeName);
                    typeElem.setPosition(position);
                    
                    elements.add(typeElem);
                    // 递归提取字段默认值中的函数（兼容不同JSQLParser版本）
                    try {
                        java.lang.reflect.Method getSpecs = null;
                        if (colDef.getClass().getMethod("getColumnSpecs") != null) {
                            getSpecs = colDef.getClass().getMethod("getColumnSpecs");
                        } else if (colDef.getClass().getMethod("getColumnSpecStrings") != null) {
                            getSpecs = colDef.getClass().getMethod("getColumnSpecStrings");
                        }
                        if (getSpecs != null) {
                            Object specListObj = getSpecs.invoke(colDef);
                            if (specListObj instanceof java.util.List) {
                                for (Object specObj : (java.util.List<?>) specListObj) {
                                    if (specObj instanceof String) {
                                        String spec = (String) specObj;
                                        if (spec.matches(".*\\w+\\(.*\\).?")) {
                                            try {
                                                Expression expr = CCJSqlParserUtil.parseExpression(spec);
                                                extractFunctionsFromExpression(expr, elements, originalSql);
                                            } catch (Exception ignore) {}
                                        }
                                    }
                                }
                            }
                        }
                    } catch (Exception ignore) {}
                }
            }
            // 递归提取表级约束中的表达式
            if (createTable.getIndexes() != null) {
                for (Object idxObj : createTable.getIndexes()) {
                    // 兼容JSQLParser不同版本的Index/Constraint类型
                    try {
                        java.lang.reflect.Method getExpression = idxObj.getClass().getMethod("getExpression");
                        Object exprObj = getExpression.invoke(idxObj);
                        if (exprObj instanceof Expression) {
                            extractFunctionsFromExpression((Expression) exprObj, elements, originalSql);
                        }
                    } catch (Exception ignore) {}
                }
            }
        }
    }

    private void extractFunctionsFromSelectBody(SelectBody selectBody, List<SQLElement> elements, String originalSql) {
        if (selectBody instanceof PlainSelect) {
            PlainSelect plainSelect = (PlainSelect) selectBody;
            if (plainSelect.getSelectItems() != null) {
                for (SelectItem item : plainSelect.getSelectItems()) {
                    if (item instanceof SelectExpressionItem) {
                        Expression expr = ((SelectExpressionItem) item).getExpression();
                        extractFunctionsFromExpression(expr, elements, originalSql);
                    }
                }
            }
            // 递归where/group by/having/order by等表达式
            if (plainSelect.getWhere() != null) {
                extractFunctionsFromExpression(plainSelect.getWhere(), elements, originalSql);
            }
            if (plainSelect.getGroupBy() != null) {
                // 使用deprecated方法但添加注解抑制警告，保持向后兼容性
                @SuppressWarnings("deprecation")
                java.util.List<Expression> groupByExpressions = plainSelect.getGroupBy().getGroupByExpressions();
                if (groupByExpressions != null) {
                    for (Expression expr : groupByExpressions) {
                    extractFunctionsFromExpression(expr, elements, originalSql);
                    }
                }
            }
            if (plainSelect.getHaving() != null) {
                extractFunctionsFromExpression(plainSelect.getHaving(), elements, originalSql);
            }
            if (plainSelect.getOrderByElements() != null) {
                for (OrderByElement obe : plainSelect.getOrderByElements()) {
                    extractFunctionsFromExpression(obe.getExpression(), elements, originalSql);
                }
            }
        } else if (selectBody instanceof SetOperationList) {
            for (SelectBody sb : ((SetOperationList) selectBody).getSelects()) {
                extractFunctionsFromSelectBody(sb, elements, originalSql);
            }
        } else if (selectBody instanceof WithItem) {
            WithItem withItem = (WithItem) selectBody;
            if (withItem.getSubSelect() != null && withItem.getSubSelect().getSelectBody() != null) {
                extractFunctionsFromSelectBody(withItem.getSubSelect().getSelectBody(), elements, originalSql);
            }
        }
    }

    private void extractFunctionsFromExpression(Expression expr, List<SQLElement> elements, String originalSql) {
        if (expr == null) {
            return;
        }
        if (expr instanceof Function) {
            Function function = (Function) expr;
            String funcName = function.getName();
            SQLElement funcElem = new SQLElement(SQLElementType.FUNCTION, funcName);
            funcElem.setValue(function.toString());
            
            // 设置位置信息
            Position position = calculatePosition(originalSql, funcName);
            funcElem.setPosition(position);
            
            elements.add(funcElem);
            // 递归参数
            if (function.getParameters() != null && function.getParameters().getExpressions() != null) {
                for (Expression param : function.getParameters().getExpressions()) {
                    extractFunctionsFromExpression(param, elements, originalSql);
                }
            }
        } else {
            // 递归所有子表达式
            expr.accept(new ExpressionDeParser() {
                @Override
                public void visit(Function function) {
                    String funcName = function.getName();
                    SQLElement funcElem = new SQLElement(SQLElementType.FUNCTION, funcName);
                    funcElem.setValue(function.toString());
                    
                    // 设置位置信息
                    Position position = calculatePosition(originalSql, funcName);
                    funcElem.setPosition(position);
                    
                    elements.add(funcElem);
                    if (function.getParameters() != null && function.getParameters().getExpressions() != null) {
                        for (Expression param : function.getParameters().getExpressions()) {
                            extractFunctionsFromExpression(param, elements, originalSql);
                        }
                    }
                }
            });
            expr.accept(new net.sf.jsqlparser.util.deparser.ExpressionDeParser());
        }
    }
}
